#include "../../include/tasktype.h"
#include "../../include/taskQueue.h"
#include "../../include/scheduler.h"
#include "../../include/myPrintk.h"
#include "../../include/wallClock.h"

extern int systime;
int waittime;
int pre_flag;

//定义各种队列
Q_LIST Waiting_Queue = {(myTCB *)0, (myTCB *)0};
Q_LIST Ready_Queue = {(myTCB *)0, (myTCB *)0};
Q_LIST Running_Queue = {(myTCB *)0, (myTCB *)0};
Q_LIST Future_Queue = {(myTCB *)0, (myTCB *)0};
Q_LIST *Waiting_Queue_Handler = &Waiting_Queue;
Q_LIST *Ready_Queue_Handler = &Ready_Queue;
Q_LIST *Running_Queue_Handler = &Running_Queue;
Q_LIST *Future_Queue_Handler = &Future_Queue;

//程序的tid从0开始，这里标记用到了几
int tid_used = 0;

void CTX_SW();

//老师给的
unsigned long **prevTSK_StackPtrAddr;
unsigned long *nextTSK_StackPtr;
void context_switch(unsigned long **prevTskStkAddr, unsigned long *nextTskStk)
{
	prevTSK_StackPtrAddr = prevTskStkAddr;
	nextTSK_StackPtr = nextTskStk;
	CTX_SW();
}

//还是老师给的
void stack_init(unsigned long **stk, void (*task)(void))
{
	*(*stk)-- = (unsigned long)tskEnd; // CS
	*(*stk)-- = (unsigned long)task;   // eip
	// pushf
	*(*stk)-- = (unsigned long)0x0202; // flag registers
	// pusha
	*(*stk)-- = (unsigned long)0xAAAAAAAA; // eax
	*(*stk)-- = (unsigned long)0xCCCCCCCC; // ecx
	*(*stk)-- = (unsigned long)0xDDDDDDDD; // edx
	*(*stk)-- = (unsigned long)0xBBBBBBBB; // ebx
	*(*stk)-- = (unsigned long)0x44444444; // esp
	*(*stk)-- = (unsigned long)0x55555555; // ebp
	*(*stk)-- = (unsigned long)0x66666666; // esi
	**stk = (unsigned long)0x77777777;	   // edi
	return;
}

//创建任务，入列，建立tid
int createTsk(void (*tskBody)(void), unsigned int arrt, unsigned int exet, unsigned int prior)
{
	myTCB *TCB = (myTCB *)kmalloc(sizeof(TCB));
	if (TCB == 0)
	{
		myPrintk(0x04, "kmalloc error: 01\n");
		return -1;
	}

	TCB->entry = tskBody;
	TCB->arrTime = arrt;
	TCB->priority = prior;
	TCB->exeTime = exet;
	TCB->stack_end = (void *)kmalloc(STACK_SIZE);
	if (TCB->stack_end == 0)
	{
		myPrintk(0x04, "kmalloc error: 02\n");
		kfree((unsigned long)TCB);
		return -1;
	}
	TCB->stack_top = TCB->stack_end + STACK_SIZE - STACK_RESERVE;
	TCB->tid = tid_used;
	tid_used++;
	stack_init((unsigned long **)&(TCB->stack_top), tskBody);
	Q_enqueue(Waiting_Queue_Handler, TCB);

#if DEBUG_CREATE_TASK
	myPrintk(0x08, "created task: %d, ", TCB->tid);
	myPrintk(0x08, "waiting queue after created:");
	Q_print(Waiting_Queue_Handler);
#endif
	return TCB->tid;
}

//找找tid在哪，销毁tcb
void destroyTsk(int tid)
{
	if (tid == idleTask->tid)
		return;
	myTCB *TCB = Q_destroy(Waiting_Queue_Handler, tid);
	if (TCB == 0)
		TCB = Q_destroy(Ready_Queue_Handler, tid);
	if (TCB == 0)
		TCB = Q_destroy(Running_Queue_Handler, tid);
	if (TCB == 0)
		return;
	kfree((unsigned long)(TCB->stack_end));
	kfree((unsigned long)TCB);
	return;
}

//挪到就绪队列
void tskStart(int tskIndex)
{
	myTCB *TCB = Q_destroy(Waiting_Queue_Handler, tskIndex);
	if (TCB == 0)
		return;
	Q_enqueue(Future_Queue_Handler, TCB);
	Q_sort(Future_Queue_Handler, FCFS);

#if DEBUG_QUEUE_FALGS
	myPrintk(0x08, "Starting task: tid: %d\n", TCB->tid);
	myPrintk(0x08, "|Waiting queue tid: ");
	printqueue(Waiting_Queue_Handler);
	myPrintk(0x08, "|Ready queue tid: ");
	printqueue(Ready_Queue_Handler);
#endif

	return;
}

//挪出来
void tskEnd()
{
	myTCB *TCB = Q_dequeue(Running_Queue_Handler);
	if (TCB == 0)
		return;
		/*if (TCB->exeTime > 0)
		{
			Q_enqueue(Ready_Queue_Handler, TCB);
			Q_sort(Ready_Queue_Handler, sch_type);
		}*/

#if DEBUG_BEGIN_END
	myPrintk(0x30, "END:    tid: %d\n", TCB->tid);
#endif

	// myPrintk(0x03, "End of %d\n", TCB->tid);

	if (TCB->tid == 4 && pre_flag)
	{
		Q_dequeue(Running_Queue_Handler);
		tskStart(idleTask->tid);
		schedule();
	}

	context_switch((unsigned long **)&(currentTask->stack_top), BspContext);
	return;
}

//调度
void startMultitask(void)
{
	// 内核栈
	BspContext = BspContextBase + STACK_SIZE - 1;
	currentTask = 0;
	Schedule();
	return;
}

void idleTskBody(void)
{
	myPrintk(0x80, "|            Idle Task          |\n");
	myPrintk(0x80, "|  God bless me here is no bug. |\n");
	while (Ready_Queue_Handler->start == 0)
		;
	return;
}

extern int sche_flag;
myTCB **return_Addr;
int stack_ptr = 0;

//初始化，只需要建立两个进程
void TaskManagerInit(void)
{

	int initTid = createTsk(initTskBody, 0, 1, 0);
	int idleTid = createTsk(idleTskBody, 0x7FFFFFFF, 1, 0);
	idleTask = Waiting_Queue_Handler->end;
	tskStart(initTid);

	myTCB *TCB = Q_destroy(Future_Queue_Handler, initTid);
	Q_enqueue(Ready_Queue_Handler, TCB);

	return_Addr = (myTCB **)kmalloc(10 * sizeof(myTCB *));

	startMultitask();
	return;
}

void stack_push(myTCB *ptr)
{

	return_Addr[stack_ptr] = ptr;
	stack_ptr++;
	for (int i = 0; i < stack_ptr; i++)
		myPrintk(0x08, "%d ", return_Addr[i]->tid);
	myPrintk(0x08, "after push\n");
	return;
}

myTCB *stack_pop()
{
	stack_ptr--;
	myTCB *ret = return_Addr[stack_ptr];
	for (int i = 0; i < stack_ptr; i++)
		myPrintk(0x08, "%d ", return_Addr[i]->tid);
	myPrintk(0x08, "after pop\n");
	return ret;
}

void Queue_manager()
{
	if (sche_flag == 0)
		return;

	// for(int i=0;i<stack_ptr;i++){
	//	myPrintk(0x90,"[%d]%d ",i,return_Addr[i]->tid);

	//}
	// myPrintk(0x80,"\n");

	myTCB *TCB = 0;
	if (currentTask != 0 && currentTask != idleTask && currentTask->exeTime > 0)
		currentTask->exeTime--;
	// myPrintk(0x02, "time:%d ready:%p\n", systime,Ready_Queue_Handler->start);
	do
	{
		TCB = Q_gettop(Future_Queue_Handler);
		if (TCB == idleTask)
			break;
		if (TCB->arrTime <= systime)
		{
			// myPrintk(0x08,"sys:%d, arr:%d, tid:%d\n",systime,TCB->arrTime,TCB->tid);
			Q_dequeue(Future_Queue_Handler);
			Q_enqueue(Ready_Queue_Handler, TCB);
			Q_sort(Ready_Queue_Handler, sch_type);
		}
	} while (TCB->arrTime <= systime);

	if (pre_flag == 0)
		return;

	int switch_flag = 0;
	myTCB *nextTCB = Q_gettop(Ready_Queue_Handler);
	if (nextTCB == idleTask)
		return;

	switch (sch_type)
	{
	case PRIO:
		if (currentTask->priority > nextTCB->priority)
		{
			// myPrintk(0x08, "Preemption from %d to %d, ptr=%d, stack[0]=%d\n", currentTask->tid, nextTCB->tid,stack_ptr,return_Addr[0]->tid);
			unsigned long **p = &BspContext;

			// myPrintk(0x08,"stack[%d]=%d\n",stack_ptr,return_Addr[stack_ptr]->tid);
			// stack_push(currentTask);

			// for(int i=0;i<stack_ptr;i++){
			//	myPrintk(0x20,"[%d]%d ",i,return_Addr[i]->tid);

			//}
			// myPrintk(0x80,"\n");

			Q_destroy(Running_Queue_Handler, currentTask->tid);
			Q_dequeue(Ready_Queue_Handler);
			Q_enqueue(Running_Queue_Handler, nextTCB);
			Q_enqueue(Ready_Queue_Handler, currentTask);
			Q_sort(Ready_Queue_Handler, sch_type);

			myTCB *temp = currentTask;

			currentTask = nextTCB;

			// myPrintk(0x08, "now is %d\n", currentTask->tid);
			// myPrintk(0x08, "run queue:");
			// Q_print(Running_Queue_Handler);
			// myPrintk(0x08, "ready queue:");
			// Q_print(Ready_Queue_Handler);

			// BspContext-=20;

			context_switch(&BspContext, currentTask->stack_top);

			// BspContext+=20;

			// for(int i=0;i<stack_ptr;i++){
			// myPrintk(0x30,"[%d]%d ",i,return_Addr[i]->tid);

			//}
			// myPrintk(0x80,"\n");

			// myPrintk(0x08, "returned from %d", currentTask->tid);
			// myPrintk(0x08,"stack[%d]=%d\n",stack_ptr,return_Addr[stack_ptr]->tid);

			// currentTask = stack_pop();
			currentTask = Q_dequeue(Ready_Queue_Handler);
			Q_enqueue(Running_Queue_Handler, currentTask);

			// myPrintk(0x08, " to %d\n", currentTask->tid);
		}
		break;

	case RR:
		// myPrintk(0x08, "curr:%d ", currentTask->tid);
		Q_destroy(Running_Queue_Handler, currentTask->tid);
		if (currentTask != idleTask)
			Q_enqueue(Ready_Queue_Handler, currentTask);
		currentTask = Q_dequeue(Ready_Queue_Handler);
		Q_enqueue(Running_Queue_Handler, currentTask);
		// myPrintk(0x08, "change to %d\n", currentTask->tid);
		context_switch(&BspContext, currentTask->stack_top);
		break;

	default:
		break;
	}

	return;
}

//调度
void Q_schedule(Q_LIST *tskhandler)
{
#if DEBUG_BEGIN_END
	static int IfPrintDebugMessage = 1;
	if (IfPrintDebugMessage)
		myPrintk(0x40, "Start schedule\n");
	IfPrintDebugMessage = (int)(currentTask != idleTask); //进入idletask后这玩应只显示一次，免得一直刷屏
#endif

	while (1)
	{
		// while(currentTask && currentTask->exeTime!=0);
		myTCB *nextTask = Q_gettop(Ready_Queue_Handler);

		// if (currentTask->exeTime == 0)
		// destroyTsk(currentTask->tid);

#if DEBUG_QUEUE_FALGS
		int curtid = (currentTask == 0) ? -1 : currentTask->tid;
		int nexttid = (nextTask == 0) ? -1 : nextTask->tid;
		myPrintk(0x08, "\nCurrent task: %d, next task: %d\n", curtid, nexttid);
#endif

		nextTask->task_state = RUNNING;
		currentTask = nextTask;

#if DEBUG_QUEUE_FALGS
		myPrintk(0x08, "Before changing the queue:\n");
		myPrintk(0X08, "|Ready   queue: ");
		printqueue(Ready_Queue_Handler);
		myPrintk(0x08, "|Running queue: ");
		printqueue(Running_Queue_Handler);
		myPrintk(0x08, "|Waiting queue: ");
		printqueue(Waiting_Queue_Handler);
#endif

		Q_dequeue(Ready_Queue_Handler);
		Q_enqueue(Running_Queue_Handler, currentTask);
		// if (currentTask == idleTask)
		//	Q_destroy(Waiting_Queue_Handler, idleTask->tid);

#if DEBUG_QUEUE_FALGS
		myPrintk(0x08, "After changed the queue:\n");
		myPrintk(0X08, "|Ready   queue: ");
		printqueue(Ready_Queue_Handler);
		myPrintk(0x08, "|Running queue: ");
		printqueue(Running_Queue_Handler);
		myPrintk(0x08, "|Waiting queue: ");
		printqueue(Waiting_Queue_Handler);
		myPrintk(0x08, "\n");
#endif
		unsigned long **p = &BspContext;

#if DEBUG_BEGIN_END
		myPrintk(0x40, "START:  tid: %d\n", currentTask->tid);
#endif
		context_switch(p, currentTask->stack_top);

		if (currentTask == idleTask)
		{
			createTsk(idleTskBody, 0x7FFFFFFF, 1, 0);
			idleTask = Waiting_Queue_Handler->end;
		}
	}
	return;
}
